package org.jaaksi.customviewdemo.view

import android.animation.ValueAnimator
import android.content.Context
import android.graphics.*
import android.text.TextPaint
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.view.ViewConfiguration
import androidx.core.graphics.drawable.toBitmap
import extension.dp
import org.jaaksi.customviewdemo.R
import kotlin.math.abs
import kotlin.math.ceil

// 选项卡控件
class TabStripView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
    // 两个圆心之间的距离
    var radiusSpace = 45.dp

    // top text 距离小圆心的距离
    var topTextSpace = 21.dp
    var bottomTextSpace = 21.dp
    var topTextSize = 16.dp
    var bottomTextSize = 18.dp
    var lineHeight = 4.dp

    var smallRadius = 5.dp
    var bitmapRadius = 13.dp
    var duration = 300L

    var topText: String? = null
    var firstText: String? = null
    var lastText: String? = null

    // 选中的bitmap
    var bitmap: Bitmap =
        resources.getDrawable(R.drawable.bg_options_checked)
            .toBitmap(bitmapRadius.toInt() * 2, bitmapRadius.toInt() * 2)

    private var paint = Paint(Paint.ANTI_ALIAS_FLAG)
    private var textPaint = TextPaint(Paint.ANTI_ALIAS_FLAG)
    private var bitmapPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    private var anim: ValueAnimator? = null

    // 当前选中的透明度
    private var selectAlpha = 1f
    private var textOffset = 0f
    private var lastSelect = -1
    private var currSelect = -1
    private var topBaselineOffset = 0f
    private var bottomBaselineOffset = 0f
    private var bottomTextHeight = 0f

    // 第一个圆心坐标
    private var firstPointX = 0f
    private var pointY = 0f

    private var count: Int = 0
    private var lastX = 0f

    // 是否是点击
    private var isClick = false

    // 最小滑动距离
    private val scaledTouchSlop = ViewConfiguration.get(getContext()).scaledTouchSlop

    // 选中回调
    var onSelectedListener: ((position: Int) -> Unit)? = null

    init {
        paint.color = resources.getColor(R.color.gray_eee)
        paint.style = Paint.Style.FILL
        paint.strokeWidth = lineHeight.toFloat()
        textPaint.color = Color.BLACK
        initFontBaselineOffset()
    }

    // 策略文本BaseLine
    private fun initFontBaselineOffset() {
        textPaint.textSize = topTextSize.toFloat()
        val fontMetrics = textPaint.fontMetrics
        topBaselineOffset = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom

        textPaint.textSize = bottomTextSize.toFloat()
        val fontMetrics2 = textPaint.fontMetrics
        bottomBaselineOffset = (fontMetrics2.bottom - fontMetrics2.top) / 2 - fontMetrics2.bottom
        bottomTextHeight = fontMetrics2.bottom - fontMetrics2.top
    }

    fun setTextTypeFace(typeFace: Typeface) {
        textPaint.typeface = typeFace
        initFontBaselineOffset()
    }

    fun setCount(count: Int) {
        check(count > 1)
        this.count = count
        calculateFirstPoint()
        invalidate()
    }

    private fun calculateFirstPoint() {
        // 计算第一个圆心坐标
        val odd = count % 2 == 1
        firstPointX = if (odd) {
            width / 2f - count / 2 * radiusSpace
        } else {
            width / 2f - (count / 2 - 0.5f) * radiusSpace
        }
        pointY = 2 * topBaselineOffset + topTextSpace
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        if (count > 1) {
            calculateFirstPoint()
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val tHeight = if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
            ceil(2 * topBaselineOffset + topTextSpace + bottomTextSpace + bottomTextHeight).toInt()
        } else {
            MeasureSpec.getSize(heightMeasureSpec)
        }

        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), tHeight)

    }

    private fun getPoint(index: Int): Float {
        return firstPointX + index * radiusSpace
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        if (count <= 1) return

        // 绘制上方文字
        textPaint.textAlign = Paint.Align.CENTER
        textPaint.textSize = topTextSize.toFloat()
        if (!topText.isNullOrEmpty() && lastSelect != -1) {
            canvas.drawText(
                topText!!,
                getPoint(lastSelect) + textOffset,
                2 * topBaselineOffset,
                textPaint
            )
        }

        // 绘制线条
        canvas.drawLine(firstPointX, pointY, getPoint(count - 1), pointY, paint)
        // 绘制非选中态
        for (index in 0 until count) {
            canvas.drawCircle(getPoint(index), pointY, smallRadius.toFloat(), paint)
        }
        // 绘制选中态
        if (lastSelect != -1 && selectAlpha != 1f) {
            bitmapPaint.alpha = ((1 - selectAlpha) * 255).toInt()
            canvas.drawBitmap(
                bitmap,
                getPoint(lastSelect) - bitmapRadius,
                pointY - bitmapRadius,
                bitmapPaint
            )
        }
        if (currSelect != -1 && selectAlpha != 0f) {
            bitmapPaint.alpha = (selectAlpha * 255).toInt()
            canvas.drawBitmap(
                bitmap,
                getPoint(currSelect) - bitmapRadius,
                pointY - bitmapRadius,
                bitmapPaint
            )
        }
        // 绘制底部文字
        textPaint.textAlign = Paint.Align.LEFT
        textPaint.textSize = bottomTextSize.toFloat()
        firstText?.let {
            canvas.drawText(
                it,
                firstPointX - smallRadius,
                pointY + bottomTextSpace + 2 * bottomBaselineOffset,
                textPaint
            )

        }

        textPaint.textAlign = Paint.Align.RIGHT
        lastText?.let {
            canvas.drawText(
                it,
                getPoint(count - 1) + smallRadius,
                pointY + bottomTextSpace + 2 * bottomBaselineOffset,
                textPaint
            )
        }

    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                lastX = event.x
                isClick = true
            }
            MotionEvent.ACTION_MOVE -> {
                isClick = abs(lastX - event.x) < scaledTouchSlop
            }

            MotionEvent.ACTION_UP -> {
                if (isClick) {
                    val index = findClickIndex(event.x, event.y)
                    if (index != -1) {
                        setSelectPosition(index)
                    }
                }
            }
        }
        return true
    }

    fun setSelectPosition(position: Int) {
        val realPos = when {
            position < 0 -> 0
            position >= count -> count
            else -> position
        }
        if (currSelect == position) return

        if (lastSelect == -1) {
            // 第一次设置，不使用动画
            currSelect = realPos
            lastSelect = realPos
            invalidate()
        } else {
            // 设置动画
            lastSelect = currSelect
            currSelect = position
            startAnim((currSelect - lastSelect).toFloat())
        }
        onSelectedListener?.invoke(realPos)
    }

    fun getSelectPosition(): Int {
        return currSelect
    }

    // 通过点击的坐标判断点击的是哪个
    private fun findClickIndex(x: Float, y: Float): Int {
        for (index in 0 until count) {
            val point = getPoint(index)
            val rectF = RectF(
                point - bitmapRadius,
                pointY - bitmapRadius,
                point + bitmapRadius,
                pointY + bitmapRadius
            )
            if (rectF.contains(x, y)) {
                return index
            }
        }
        return -1
    }

    private fun startAnim(offset: Float) {
        anim?.end()
        anim = ValueAnimator.ofFloat(0f, offset).apply {
            duration = this@TabStripView.duration
            addUpdateListener {
                val value = it.animatedValue as Float
                textOffset = value * radiusSpace
                selectAlpha = if (value == 0f) {
                    0f
                } else {
                    value / offset
                }

                postInvalidate()
            }
            start()
        }
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        anim?.cancel()
        bitmap.recycle()
    }
}